# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: Vue应用登录测试 >> 登录页面视觉测试
- Location: E:\studyvues\xixunvue\tests\vue-login-allure.spec.js:182:3

# Error details

```
Error: page.goto: Target page, context or browser has been closed
Call log:
  - navigating to "http://localhost:8080/", waiting until "load"

    at callback (E:\studyvues\xixunvue\tests\vue-login-allure.spec.js:121:18)
    at body (E:\studyvues\xixunvue\tests\vue-login-allure.spec.js:82:28)
    at body (E:\studyvues\xixunvue\node_modules\allure-js-commons\src\facade.ts:113:48)
    at call (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:13:56)
    at tryCatch (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at Generator._invoke (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at Generator.next (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at asyncGeneratorStep (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at _next (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1
    at E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1
    at call (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:13:23)
    at tryCatch (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at Generator._invoke (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at Generator.next (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at asyncGeneratorStep (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at _next (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1
    at AllurePlaywrightTestRuntime.apply (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:2:1)
    at AllurePlaywrightTestRuntime.step (E:\studyvues\xixunvue\node_modules\allure-playwright\src\runtime.ts:14:4)
    at callRuntimeMethod (E:\studyvues\xixunvue\node_modules\allure-js-commons\src\facade.ts:21:27)
    at Object.step (E:\studyvues\xixunvue\node_modules\allure-js-commons\src\facade.ts:113:10)
    at Object.step (E:\studyvues\xixunvue\node_modules\allure-playwright\src\legacy.ts:147:48)
    at testStep (E:\studyvues\xixunvue\tests\vue-login-allure.spec.js:79:23)
    at E:\studyvues\xixunvue\tests\vue-login-allure.spec.js:120:11
```

# Test source

```ts
   21 |         fs.mkdirSync(allureDir, { recursive: true });
   22 |       }
   23 |       
   24 |       // 生成唯一的轨迹文件名
   25 |       const allureTracePath = path.join(allureDir, `trace-${Date.now()}.zip`);
   26 |       // 复制轨迹文件到allure-results目录
   27 |       fs.writeFileSync(allureTracePath, traceContent);
   28 |       
   29 |       // 创建跳转到Playwright查看器的HTML文件
   30 |       const viewerLinkContent = `
   31 |         <!DOCTYPE html>
   32 |         <html>
   33 |         <head>
   34 |           <title>Playwright Trace Viewer</title>
   35 |           <style>
   36 |             body { font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; }
   37 |             .container { max-width: 800px; margin: 0 auto; }
   38 |             .btn { display: inline-block; background: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px; }
   39 |             pre { background: #f4f4f4; padding: 10px; border-radius: 4px; overflow-x: auto; }
   40 |           </style>
   41 |         </head>
   42 |         <body>
   43 |           <div class="container">
   44 |             <h1>Playwright 轨迹查看器</h1>
   45 |             <p>您可以通过以下命令查看测试轨迹:</p>
   46 |             <pre>npx playwright show-trace ${tracePath}</pre>
   47 |             <p>或者点击下面的按钮打开轨迹查看器:</p>
   48 |             <a class="btn" href="https://trace.playwright.dev/" target="_blank">打开轨迹查看器</a>
   49 |             <p>然后在轨迹查看器中上传以下文件:</p>
   50 |             <pre>${tracePath}</pre>
   51 |           </div>
   52 |         </body>
   53 |         </html>
   54 |       `;
   55 |       
   56 |       // 保存HTML链接文件
   57 |       const viewerLinkPath = path.join(allureDir, `trace-viewer-link-${Date.now()}.html`);
   58 |       fs.writeFileSync(viewerLinkPath, viewerLinkContent);
   59 |       
   60 |       console.log(`轨迹文件已复制到 ${allureTracePath}`);
   61 |       console.log(`查看轨迹链接已保存到 ${viewerLinkPath}`);
   62 |       
   63 |       // 通过allure API直接添加附件，更新为正确的API
   64 |       allure.attachment('trace.zip', fs.readFileSync(tracePath), 'application/zip');
   65 |       allure.attachment('trace-viewer-link.html', viewerLinkContent, 'text/html');
   66 |     } catch (error) {
   67 |       console.error('添加轨迹文件时出错:', error);
   68 |     }
   69 |   } else {
   70 |     console.log(`未找到轨迹文件: ${tracePath}`);
   71 |   }
   72 | }
   73 |
   74 | // 保存测试步骤
   75 | async function testStep(name, callback) {
   76 |   console.log(`步骤: ${name}`);
   77 |   
   78 |   // 使用正确的allure API记录步骤
   79 |   return await allure.step(name, async () => {
   80 |     try {
   81 |       // 执行回调
   82 |       const result = await callback();
   83 |       return result;
   84 |     } catch (error) {
   85 |       console.error(`步骤 "${name}" 执行失败:`, error);
   86 |       throw error;
   87 |     }
   88 |   });
   89 | }
   90 |
   91 | // 保存测试附件
   92 | function saveScreenshot(name, content) {
   93 |   try {
   94 |     // 确保allure-results目录存在
   95 |     const allureDir = path.join(process.cwd(), 'allure-results');
   96 |     if (!fs.existsSync(allureDir)) {
   97 |       fs.mkdirSync(allureDir, { recursive: true });
   98 |     }
   99 |     
  100 |     // 生成唯一文件名
  101 |     const filename = `${name.replace(/\s+/g, '-')}-${Date.now()}.png`;
  102 |     const filepath = path.join(allureDir, filename);
  103 |     
  104 |     // 保存附件
  105 |     fs.writeFileSync(filepath, content);
  106 |     console.log(`保存截图 ${name} 到 ${filepath}`);
  107 |     
  108 |     // 通过allure API添加截图，更新为正确的API
  109 |     allure.attachment(name, content, 'image/png');
  110 |     
  111 |     return filepath;
  112 |   } catch (error) {
  113 |     console.error(`保存截图 ${name} 时出错:`, error);
  114 |   }
  115 | }
  116 |
  117 | test.describe('Vue应用登录测试', () => {
  118 |   test.beforeEach(async ({ page }) => {
  119 |     // 添加测试步骤
  120 |     await testStep('打开登录页面', async () => {
> 121 |       await page.goto('/');
      |                  ^ Error: page.goto: Target page, context or browser has been closed
  122 |       await page.waitForLoadState('networkidle');
  123 |     });
  124 |     
  125 |     // 确保存在test-results目录
  126 |     require('fs').mkdirSync('test-results', { recursive: true });
  127 |     
  128 |     // 添加截图作为附件
  129 |     await testStep('捕获初始页面截图', async () => {
  130 |       const screenshot = await page.screenshot();
  131 |       saveScreenshot('登录页面初始截图', screenshot);
  132 |     });
  133 |   });
  134 |
  135 |   test('可以看到登录表单并尝试登录', async ({ page }, testInfo) => {
  136 |     // 设置测试信息，更新为正确的API
  137 |     allure.severity('critical');
  138 |     allure.description('验证登录表单可见并尝试使用默认凭据登录');
  139 |     
  140 |     // 等待登录表单元素加载
  141 |     await testStep('等待登录表单加载', async () => {
  142 |       await page.waitForSelector('form', { state: 'visible' });
  143 |     });
  144 |     
  145 |     // 查找表单元素并执行登录
  146 |     await testStep('定位登录表单元素', async () => {
  147 |       const usernameInput = page.locator('input[type="text"], input[name="username"]').first();
  148 |       const passwordInput = page.locator('input[type="password"], input[name="password"]').first();
  149 |       const loginButton = page.locator('button[type="submit"], button:has-text("登录"), .login-btn').first();
  150 |       
  151 |       await expect(usernameInput).toBeVisible();
  152 |       await expect(passwordInput).toBeVisible();
  153 |       await expect(loginButton).toBeVisible();
  154 |       
  155 |       // 填写表单
  156 |       await testStep('填写登录凭据', async () => {
  157 |         await usernameInput.fill('admin');
  158 |         await passwordInput.fill('admin');
  159 |         
  160 |         // 保存登录表单填写后的截图
  161 |         const formFilledScreenshot = await page.screenshot();
  162 |         saveScreenshot('登录表单填写完成', formFilledScreenshot);
  163 |       });
  164 |       
  165 |       // 提交表单
  166 |       await testStep('点击登录按钮', async () => {
  167 |         await loginButton.click();
  168 |         await page.waitForLoadState('networkidle');
  169 |       });
  170 |     });
  171 |     
  172 |     // 验证登录结果
  173 |     await testStep('验证登录结果', async () => {
  174 |       const afterLoginScreenshot = await page.screenshot();
  175 |       saveScreenshot('登录后页面状态', afterLoginScreenshot);
  176 |     });
  177 |     
  178 |     // 为这个测试添加轨迹
  179 |     await attachTraceToAllure(testInfo);
  180 |   });
  181 |
  182 |   test('登录页面视觉测试', async ({ page }, testInfo) => {
  183 |     // 设置测试信息，更新为正确的API
  184 |     allure.severity('minor');
  185 |     allure.description('视觉测试 - 检查登录页面UI布局');
  186 |     
  187 |     // 捕获完整页面截图
  188 |     await testStep('捕获完整页面截图', async () => {
  189 |       const fullPageScreenshot = await page.screenshot({ fullPage: true });
  190 |       saveScreenshot('登录页面完整截图', fullPageScreenshot);
  191 |     });
  192 |     
  193 |     // 为这个测试添加轨迹
  194 |     await attachTraceToAllure(testInfo);
  195 |   });
  196 | }); 
```